package com.zero.manage.web.components.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.zero.manage.web.components.base.BaseService;
import com.zero.manage.web.components.dao.DatabaseInfoDao;
import com.zero.manage.web.components.dto.GenDto;
import com.zero.manage.web.components.entity.DatabaseInfoEntity;
import com.zero.manage.web.components.entity.QDatabaseInfoEntity;
import com.zero.manage.web.components.query.DatabaseInfoQuery;
import com.zero.manage.web.components.service.DatabaseInfoService;
import io.gitee.zerowsh.enums.ToolEnums;
import com.zero.manage.web.utils.generate.DatabaseDao;
import com.zero.manage.web.utils.generate.GenUtils;
import io.gitee.zerowsh.enums.ResultEnums;
import io.gitee.zerowsh.util.PublicResult;
import io.gitee.zerowsh.util.RsaUtil;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.sql.Connection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.zip.ZipOutputStream;

@Service
@Log4j2
public class DatabaseInfoServiceImpl extends BaseService<DatabaseInfoEntity, String, DatabaseInfoDao, DatabaseInfoQuery> implements DatabaseInfoService {
    private QDatabaseInfoEntity databaseInfoEntity = QDatabaseInfoEntity.databaseInfoEntity;

    @Value("${rsa-private-key}")
    private String rsaPrivateKey;
    @Autowired
    private DynamicRoutingDataSource ds;

    private Optional<PublicResult> testConnect(DatabaseInfoEntity databaseInfoEntity, ResultEnums resultEnums) {
        String decrypt = RsaUtil.decrypt(databaseInfoEntity.getPassword(), rsaPrivateKey);
        if (StrUtil.isBlank(decrypt)) {
            return Optional.of(PublicResult.resultEnums(resultEnums, "密码错误"));
        }
        databaseInfoEntity.setPassword(decrypt);
        try (Connection connection = DatabaseDao.getConnection(databaseInfoEntity)) {
            if (Objects.isNull(connection)) {
                return Optional.of(PublicResult.resultEnums(resultEnums, "数据库连接信息异常"));
            }
        } catch (Exception e) {
            log.error("数据库连接异常", e);
            return Optional.of(PublicResult.resultEnums(resultEnums, "数据库连接信息异常"));
        }
        return Optional.empty();
    }

    @Override
    public PublicResult add(DatabaseInfoEntity databaseInfoEntity) {
        Optional<PublicResult> publicResult = testConnect(databaseInfoEntity, ResultEnums.ADD_FAIL);
        return publicResult.orElseGet(() -> super.add(databaseInfoEntity));
    }

    @Override
    public PublicResult update(DatabaseInfoEntity databaseInfoEntity) {
        Optional<PublicResult> publicResult = testConnect(databaseInfoEntity, ResultEnums.UPDATE_FAIL);
        return publicResult.orElseGet(() -> super.update(databaseInfoEntity));
    }

    @Override
    public PublicResult select() {
        return PublicResult.queryOk(jpa.select(databaseInfoEntity.id, databaseInfoEntity.name).from(databaseInfoEntity).fetch().stream()
                //转换集合内的数据
                .map(tuple -> {
                    Map<String, Object> map = new HashMap<>(3);
                    map.put("key", tuple.get(databaseInfoEntity.id));
                    map.put("value", tuple.get(databaseInfoEntity.name));
                    return map;
                }).collect(Collectors.toList()));
    }


    @Override
    @DS("#databaseInfoId")
    public PublicResult getCatalogs(String databaseInfoId) {
        return PublicResult.queryOk(DatabaseDao.handleDataSource(ds, databaseInfoId).getCatalogs());
    }

    @Override
    @DS("#databaseInfoId")
    public PublicResult getTableInfo(String databaseInfoId, String catalog) {
        return PublicResult.queryOk(DatabaseDao.handleDataSource(ds, databaseInfoId).getTableInfo(catalog));
    }

    @Override
    @DS("#genDto.databaseInfoId")
    public PublicResult generatorCode(GenDto genDto, HttpServletResponse response) throws IOException {
        ToolEnums.WhetherEnums download = genDto.getDownload();
        if (Objects.equals(download, ToolEnums.WhetherEnums.T)) {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ZipOutputStream zip = new ZipOutputStream(outputStream);
            GenUtils.generatorCode(ds, genDto, zip);
            IOUtils.closeQuietly(zip);
            byte[] data = outputStream.toByteArray();
            response.reset();
            response.setHeader("Content-Disposition", "attachment; filename=\"generator.zip\"");
            response.addHeader("Content-Length", "" + data.length);
            response.addHeader("Access-Control-Allow-Origin", "*");
            response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
            response.addHeader("Access-Control-Allow-Headers", "Content-Type");
            response.setContentType("application/octet-stream; charset=UTF-8");
            IOUtils.write(data, response.getOutputStream());
        } else {
            GenUtils.generatorCode(ds, genDto);
        }
        return PublicResult.resultEnums(ResultEnums.GEN_OK);
    }
}
